package com.initialize.common.tool.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.initialize.commom.config.exception.TokenException;
import com.initialize.commom.config.system.SiteConfig;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
public class JwtTokenTool {
    // 过期时间，单位毫秒
    private static final long EXPIRE_TIME = 7 * 24 * 3600 * 1000;

    //秘钥
    private static String secret =
            "mkP8AkG$THUINxziAAnuRRcoQk!v@fid"
                    + "Qhi8fns6KFc!uxy@JEF*wmyLJsXoT^qs"
                    + "8PG0x6UuTMiaUuWKlXz#*DY9Zvw8Fis&";

    /**
     * 创建Token
     *
     * @param _id
     * @param login
     * @param psd
     * @return
     */
    public static String createToken(int _id, String login, String psd) {
        Date newDate = new Date();
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);

        Map<String, Object> stringObjectMap = new LinkedHashMap<>();
        stringObjectMap.put("_id", _id);
        stringObjectMap.put("login", login);
        stringObjectMap.put("psd", psd);

        byte[] keyBytes = secret.getBytes();
        SecretKey key = Keys.hmacShaKeyFor(keyBytes);

        return Jwts.builder()
                .setClaims(stringObjectMap)
                .setIssuedAt(newDate)
                .setExpiration(date)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 获取网络请求的token
     *
     * @param httpServletRequest
     * @return
     */
    public static String getUserToken(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getHeader("user_token");
    }

    /**
     * 验证
     *
     * @param token 用户的token
     * @param psd
     * @return
     * @throws TokenException
     */
    public static boolean verification(String token, String psd) throws TokenException {

        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(psd)).build();
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            throw new TokenException("401");
        }
        return true;
    }

    /**
     * 获取token的到期时间
     *
     * @param token 用户的token
     * @return 到期时间
     */
    public static Date getTheExpirationTime(String token) {
        return JWT.decode(token).getExpiresAt();
    }

    /**
     * 通过网络请求的token直接返回当前有效的操作者id
     *
     * @param httpServletRequest
     * @return
     */
    public static int getId(HttpServletRequest httpServletRequest) {
        String userToken = getUserToken(httpServletRequest);

        if (testEnvironment(userToken)) {
            return 2;
        }
        Claims claimsFromToken = getClaimsFromToken(userToken);
        Object id = claimsFromToken.get("_id");
        return (int) id;
    }

    /**
     * 从token中获取claim
     *
     * @param token token
     * @return claim
     */
    public static Claims getClaimsFromToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret.getBytes())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
            throw new IllegalArgumentException("Token invalided.");
        }
    }

    /**
     * 判断是否是测试环境
     *
     * @param userToken
     * @return
     */
    private static boolean testEnvironment(String userToken) {
        if (SiteConfig.FLAG) {
            return userToken.equals(TokenUtil.TEST_TOKEN);
        }
        return false;
    }


}
